import Control.Monad (filterM)
import System.Directory (Permissions(..), getModificationTime, getPermissions)
--import System.Time (ClockTime(..))
import System.FilePath (takeExtension)
import Control.Exception (bracket, handle)
import System.IO (IOMode(..), hClose, hFileSize, openFile)
import Data.Time.Clock (UTCTime(..))
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception (bracket, handle, SomeException)

-- the function we wrote earlier
import RecursiveContents (getRecursiveContents)
import GHC.IO.Handle.Types
import GHC.Exception


type Predicate =  FilePath      -- path to directory entry
               -> Permissions   -- permissions
               -> Maybe Integer -- file size (Nothing if not file)
               -> UTCTime     -- last modified
               -> Bool

{-
returnSize :: GHC.IO.Handle.Types.Handle -> IO (Maybe Integer)         
returnSize h = do
    size <- hFileSize h
    return (Just size) 
-}
returnnothing :: SomeException -> IO (Maybe a)
returnnothing _ = return Nothing
    
getFileSize :: FilePath -> IO (Maybe Integer)
getFileSize path = handle returnnothing $
  bracket (openFile path ReadMode) hClose $ \h -> do
    size <- hFileSize h
    return (Just size) 

    
          {-    
getFileSize :: FilePath -> IO (Maybe Integer)
getFileSize path = handle (\_ -> return Nothing)  $
  bracket (openFile path ReadMode) hClose $ \h -> do
    size <- hFileSize h
    return (Just size)
    -}  
betterFind :: Predicate -> FilePath -> IO [FilePath]

betterFind p path = getRecursiveContents path >>= filterM check
    where check name = do
            perms <- getPermissions name
            size <- getFileSize name
            modified <- getModificationTime name
            return (p name perms size modified)               
{-
betterFind (sizeP `equalP` 1024)  "."

-}
                         
            
    
              
type InfoP a =  FilePath        -- path to directory entry
             -> Permissions     -- permissions
             -> Maybe Integer   -- file size (Nothing if not file)
             -> UTCTime       -- last modified
             -> a               
               
               
sizeP :: InfoP Integer
sizeP _ _ (Just size) _ = size
sizeP _ _ Nothing     _ = -1        


pathP path _ _ _ = path

equalP :: (Eq a) => InfoP a -> a -> InfoP Bool
equalP f k = \w x y z -> f w x y z == k

equalP' :: (Eq a) => InfoP a -> a -> InfoP Bool
equalP' f k w x y z = f w x y z == k

greaterP' :: (Eq a) => InfoP a -> a -> InfoP Bool
greaterP' f k w x y z = f w x y z > k


lesserP' :: (Eq a) => InfoP a -> a -> InfoP Bool
lesserP' f k w x y z = f w x y z < k

     {-
betterFind (sizeP `equalP` 1024)  "."

-}          
liftP :: (a -> b -> c) -> InfoP a -> b -> InfoP c
liftP q f k w x y z = f w x y z `q` k

greaterP, lesserP :: (Ord a) => InfoP a -> a -> InfoP Bool
greaterP = liftP (>)
lesserP = liftP (<)

liftP2 :: (a -> b -> c) -> InfoP a -> InfoP b -> InfoP c
liftP2 q f g w x y z = f w x y z `q` g w x y z

andP = liftP2 (&&)
orP = liftP2 (||)

{-
myTest2 = (liftPath takeExtension `equalP` ".cpp") `andP`
          (sizeP `greaterP` 131072)
          
          
-}
constP :: a -> InfoP a
constP k _ _ _ _ = k

liftP' q f k w x y z = f w x y z `q` constP k w x y z


myTest path _ (Just size) _ =
    takeExtension path == ".cpp" && size > 13072
myTest _ _ _ _ = False


liftPath :: (FilePath -> a) -> InfoP a
liftPath f w _ _ _ = f w

myTest2 = (liftPath takeExtension `equalP` ".cpp") `andP`
          (sizeP `greaterP` 13072)
          
(==?) = equalP
(&&?) = andP
(>?) = greaterP

myTest3 = (liftPath takeExtension ==? ".cpp") &&? (sizeP >? 13072)          
  
infix 4 ==?
infixr 3 &&?
infix 4 >?
myTest4 = liftPath takeExtension ==? ".cpp" &&? sizeP >? 131072



    